﻿using System.Collections.Specialized;
using KinonekoSoftware.CodariaDB.Documents.Keywords;
using KinonekoSoftware.CodariaDB.Utils;
using KinonekoSoftware.Studio.Models.Theories;
using KinonekoSoftware.Studio.Utils;

namespace KinonekoSoftware.Studio.Pages.Theories
{
    partial class WorldViewConfigViewModel
    {

        private Dictionary<string, KeywordCatalog> _KeywordIDMap;

        private bool           _hasFolder;
        private KeywordCatalog _currentKeywordCatalog;
        
        private void InitializeKeywords()
        {
            var rebuild = ArrayRebuild.RebuildCatalogs(_keywordCatalogRoot.KeywordCatalogs, out _KeywordIDMap);
            
            KeywordCatalogs.CollectionChanged += OnCatalogsChanged; 
            KeywordCatalogs.AddMany(rebuild, true);
            Keywords.AddMany(_keywordCatalogRoot.KeywordLists.Select(x => x.Name), true);
        }

        private void SaveKeywordCatalogs()
        {
            _repository.Set(_keywordCatalogRoot);
        }
        
        
        private void OnCatalogsChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            HasFolder = KeywordCatalogs.Count > 0;
        }

        
        //-------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------


        private async void DoNewKeywordCatalogCommand(KeywordCatalog parent)
        {
            var r = await NewKeywordCatalogViewModel.New();

            if (!r.IsFinished)
            {
                return;
            }

            var id  = ID.Get();
            var catalog = r.Value;

            if (parent is null) 
            {
                KeywordCatalogs.Add(catalog);
            }
            else
            {
                catalog.ParentID =   parent.Id;
                catalog.Index    =   parent.Children.Count;
                parent.Children.Add(catalog);
            }
            
            _KeywordIDMap.Add(id, catalog);
            _keywordCatalogRoot.KeywordCatalogs.Add(catalog);
            SaveKeywordCatalogs();
        }

        private async void DoMoveKeywordCatalogCommand(KeywordCatalog element)
        {
            if (element is null)
            {
                return;
            }

            var context = new DialogContext();
            var target = new PseudoCatalog
            {
                Id              = element.Id,
                Children        = new ObservableCollection<PseudoCatalog>(),
                ParentID        = element.ParentID,
                Name            = element.Name,
                IsTargetCatalog = true,
            };


            var rebuild = ArrayRebuild.Rebuild(_keywordCatalogRoot.KeywordCatalogs
                                                           .Select(x => new PseudoCatalog
                                                           {
                                                               Id       = x.Id,
                                                               ParentID = x.ParentID,
                                                               Name     = x.Name,
                                                               Children = new ObservableCollection<PseudoCatalog>(),
                                                           })
                                                           .Where(x => x.Id != element.Id)
                                                           .ToList(), out var pseudoCatalogMap);

            context.Set(MoveCatalogViewModel.PseudoCatalogs, rebuild);
            context.Set(MoveCatalogViewModel.PseudoCatalogMap, pseudoCatalogMap);
            context.Set(MoveCatalogViewModel.TargetElement, target);

            var r = await Dialog<PseudoCatalog, MoveCatalogViewModel>(context);

            if (!r.IsFinished)
            {
                return;
            }

            //
            // final done

            if (element.ParentID == target.ParentID && target.Index == element.Index)
            {
                return;
            }


            // remove default catalog
            RemoveOldPosition(element);
            MoveToNewPosition(element, target.ParentID, target.Index);

            //
            // save
            SaveKeywordCatalogs();
        }

        private void RemoveOldPosition(KeywordCatalog element)
        {
            if (element.IsRoot())
            {
                KeywordCatalogs.Remove(element);
            }
            else if (_KeywordIDMap.TryGetValue(element.ParentID, out var parent))
            {
                parent.Children.Remove(element);
            }

            _keywordCatalogRoot.KeywordCatalogs.Remove(element);
        }

        private void MoveToNewPosition(KeywordCatalog element, string newParentId, int index)
        {
            if (string.IsNullOrEmpty(newParentId))
            {
                KeywordCatalogs.Insert(index, element);
                for (var i = 0; i < KeywordCatalogs.Count; i++)
                {
                    TreeCatalogs[i].Index = i;
                }
            }
            else if(_KeywordIDMap.TryGetValue(newParentId, out var newParent))
            {
                newParent.Children.Insert(index, element);
                    
                for (var i = 0; i < newParent.Children.Count; i++)
                {
                    newParent.Children[i].Index = i;
                }
            }
                
            //
            // set new parent id
            element.ParentID = newParentId;
        }

        private async void DoEditKeywordCatalogCommand(KeywordCatalog element)
        {
            if (element is null)
            {
                return;
            }

            var r   = await SingleText("新建文件夹", "输入要创建的文件夹名字");
            var val = r.Value;

            if (!r.IsFinished)
            {
                return;
            }

            element.Name = val;
            _repository.Set(_keywordCatalogRoot);
        }

        private void DoShiftUpKeywordCatalogCommand(KeywordCatalog element)
        {
            if (element is null)
            {
                return;
            }

            if (element.IsRoot())
            {
                KeywordCatalogs.ShiftUp(element, () =>
                {
                    for (var i = 0; i < KeywordCatalogs.Count; i++)
                    {
                        TreeCatalogs[i].Index          = i;
                    }
                });

            }
            else if (_KeywordIDMap.TryGetValue(element.ParentID, out var parent))
            {

                parent.Children.ShiftUp(element, () =>
                {
                    for (var i = 0; i < parent.Children.Count; i++)
                    {
                        parent.Children[i].Index = i;
                    }
                });
            }

            SaveKeywordCatalogs();
        }

        private void DoShiftDownKeywordCatalogCommand(KeywordCatalog element)
        {

            if (element is null)
            {
                return;
            }

            if (element.IsRoot())
            {
                KeywordCatalogs.ShiftDown(element, () =>
                {
                    for (var i = 0; i < KeywordCatalogs.Count; i++)
                    {
                        TreeCatalogs[i].Index = i;
                    }
                });

            }
            else if (_KeywordIDMap.TryGetValue(element.ParentID, out var parent))
            {

                parent.Children.ShiftDown(element, () =>
                {
                    for (var i = 0; i < parent.Children.Count; i++)
                    {
                        parent.Children[i].Index = i;
                    }
                });
            }

            SaveKeywordCatalogs();
        }

        #region Remove
        //
        // private void RemoveThis(KeywordCatalog element)
        // {
        //     var queue = new Queue<KeywordCatalog>();
        //     var set   = new HashSet<KeywordCatalog>();
        //     
        //     queue.OnNext(element);
        //
        //     while (queue.Count > 0)
        //     {
        //         var item = queue.Dequeue();
        //
        //         if (string.IsNullOrEmpty(item.ParentID))
        //         {
        //             continue;
        //         }
        //
        //         set.Add(item);
        //     }
        //
        //     foreach (var catalog in set)
        //     {
        //         //
        //         // TODO:
        //         _catalogRoot.KeywordCatalogs.Remove(catalog);
        //     }
        // }
        
        private async void DoRemoveKeywordCatalogCommand(KeywordCatalog element)
        {
            if (element is null)
            {
                return;
            }
            
            if (!await RemoveItem())
            {
                return;
            }

            if (element.IsRoot())
            {
                KeywordCatalogs.Remove(element);

                if (element.Children is not null &&
                    element.Children.Count > 0)
                {
                    foreach (var child in element.Children)
                    {
                        child.ParentID = null;
                        KeywordCatalogs.Add(child);
                    }
                }
            }
            else if(_KeywordIDMap.TryGetValue(element.ParentID, out var parent))
            {
                if (element.Children is not null &&
                    element.Children.Count > 0)
                {

                    foreach (var child in element.Children)
                    {
                        child.ParentID = parent.Id;
                        parent.Children.Add(child);
                    }

                    parent.Children.Remove(element);
                    element.ParentID = null;

                }
                
            }

            _keywordCatalogRoot.KeywordCatalogs.Remove(element);
            _KeywordIDMap.Remove(element.Id);
            SaveKeywordCatalogs();
        }

        #endregion

        private readonly EnumValuesFilteringFactory<InstanceType> _filteredInstanceType;
        
        public ICommandEX NewKeywordCatalogCommand       { get; }
        public ICommandEX EditKeywordCatalogCommand      { get; }
        public ICommandEX MoveKeywordCatalogCommand      { get; }
        public ICommandEX ShiftUpKeywordCatalogCommand   { get; }
        public ICommandEX ShiftDownKeywordCatalogCommand { get; }
        public ICommandEX RemoveKeywordCatalogCommand    { get; }

        public ObservableCollection<KeywordCatalog> KeywordCatalogs { get; }
        public ObservableCollection<KeywordCatalog> KeywordChildren { get; }
        public IEnumerable<InstanceType>            InstanceTypes   => _filteredInstanceType.Values;
        public ObservableCollection<string>         Keywords        { get; }

        /// <summary>
        /// 当前目录
        /// </summary>
        public KeywordCatalog CurrentKeywordCatalog
        {
            get => _currentKeywordCatalog;
            set
            {
                if (value is not null)
                {
                    KeywordChildren.AddMany(value.Children, true);
                }
                
                SetValue(ref _currentKeywordCatalog, value);
                RaiseUpdated(nameof(CurrentKeywordCatalogName));
                RaiseUpdated(nameof(CurrentKeywordCatalogType));
            }
        }

        /// <summary>
        /// 当前目录的类型
        /// </summary>
        public string CurrentKeywordCatalogName
        {
            get
            {
                if (_currentKeywordCatalog is not null)
                {
                    return _currentKeywordCatalog.Name;
                }

                return string.Empty;
            }
            set
            {

                if (_currentKeywordCatalog is not null)
                {
                    _currentKeywordCatalog.Name = value;
                    SaveKeywordCatalogs();
                }
            }
        }

        /// <summary>
        /// 当前目录的类型
        /// </summary>
        public InstanceType CurrentKeywordCatalogType
        {
            
            get
            {
                if (_currentKeywordCatalog is not null)
                {
                    return _currentKeywordCatalog.Type;
                }

                return InstanceType.Instance;
            }
            set
            {

                if (_currentKeywordCatalog is not null)
                {
                    _currentKeywordCatalog.Type = value;
                    SaveKeywordCatalogs();
                }
            }
        }
        
        public bool HasFolder
        {
            get => _hasFolder;
            private set => SetValue(ref _hasFolder, value);
        }
    }
}